import time
from webutils.layers.services import ManagerProxy

from .. import managers
from .base import BaseService


class Handwriting(BaseService):
    """Provide a file like api
    """
    required_context = ['room_id', 'user_id']
    handwriting = ManagerProxy(managers.Handwriting)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._position = 0

    def tell(self):
        return self._position

    def seek(self, position):
        assert position >= 0
        self._position = position

    async def write(self, frame):
        # 清屏指令，需要清除历史数据
        if frame.data_frame.action == 0:
            await self.handwriting.clear()
            update_time = managers.HandwritingRefreshTime(
                self,
                room_id=self.room_id,
            )
            await update_time.update(self.user_id, time.time())
        # only support append mode
        position = await self.handwriting.append(frame)
        # in case of two request write in the same time
        self._position = max(self._position, position)
        return self._position

    async def sync_position(self, last_refresh_time, position):
        # A 用户的笔记清空后
        # B / C 需要从头获取笔记数据，即更新offset
        # 维护 A 清空笔记的时间
        # B / C 记录从何次更新拉的笔记
        # 如果该时间小于 A 清空笔记的时间，需要重置offset为0
        # 否则，使用当前的offset
        update_time = managers.HandwritingRefreshTime(
            self,
            room_id=self.room_id,
        )
        update_at = await update_time.get(self.user_id) or 0
        update_at = float(update_at)
        if last_refresh_time < update_at:
            last_refresh_time = update_at
            position = 0
        self.seek(position)
        return last_refresh_time, self.tell()

    async def read(self, size=100):
        end = self._position + size
        lst = await self.handwriting.slicing(self._position, end)
        if not lst:
            return None
        lst = list(lst)
        content = lst[0].to_bytes()
        self._position += 1
        for frame in lst[1:]:
            content += frame.value
            self._position += 1
        return content
